/**
 * Copyright (2017, ) Institute of Software, Chinese Academy of Sciences
 */
package cn.abcsys.devops.application.controller;
import cn.abcsys.devops.application.model.ApplicationCore;
import cn.abcsys.devops.application.model.ApplicationEvents;
import cn.abcsys.devops.application.model.ParamsApplication;
import cn.abcsys.devops.application.model.ParamsDeployerConversion;
import cn.abcsys.devops.application.service.ApplicationService;
import cn.abcsys.devops.application.service.CheckService;
import cn.abcsys.devops.application.service.DbService;
import cn.abcsys.devops.application.service.EventsService;
import cn.abcsys.devops.commons.utils.IPUtils;
import cn.abcsys.devops.commons.utils.NumberUtils;
import cn.abcsys.devops.commons.utils.ObjectUtils;
import cn.abcsys.devops.commons.utils.StringUtils;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author xuyuanjia2017@otcaix.iscsa.ac.cn
 * @date 2017/6/20 0020
 * say sth.
 */
@Controller
public class ApplicationController {

    @Resource(name="applicationService")
    private ApplicationService appService;

    @Resource(name="eventsService")
    private EventsService eventsService;

    @Resource(name="dbService")
    private DbService dbService;

    @Resource(name="checkService")
    private CheckService checkService;

    private Map<String,Object> errorParams(){
        return new HashMap<String,Object>(){
            {
                put("message","参数错误，请修改后重新输入！");
                put("success",false);
            }
        };
    }

    /**********************************************************
     * 
     *                   Create Application
     * 
     **********************************************************/
    
    @RequestMapping("createAppFromImage.do")
    public @ResponseBody
    Map<String, Object> createAppFromImage(ParamsApplication paramsApplication) {
        if(!this.checkService.checkCreateAppFromImage(paramsApplication)){
            return this.errorParams();
        }
        System.out.println(paramsApplication.configBasic.getConfigBasicMemory());
        Map<String,Object> application = createApplicationConfiguration(paramsApplication);

        // application = createApplicationBy(appConfig)
        // if(invalidApplicationInfo(appInfo)) {
        //    return failMessage
        // }
//        Map<String,Object> applicationInfo = dbService.saveOrDoNothingApplicationAllInfo(paramsApplication);

        // deployStatus = deployApplication(application)
        // return deployStatus

        List<ParamsApplication> deployerParams = this.dbService.getAllInfoByApplicationInstanceRelationIds((String)application.get("applicationInstanceRelation"));
        try {
            application.put("createRcResults",this.batchCreateRc(deployerParams, paramsApplication.getIp()));
        } catch (Exception e) {
            e.printStackTrace();
            application.put("success",false);
            application.put("message","应用已经成功构建，但是K8s集群环境异常，请联系管理员或者修改参数重新配置！");
        }

        // service = getService("IP", "kubernetes");
        // service.batchbatchCreateApplication(deployerParams)

        return application;
    }

	private Map<String, Object> createApplicationConfiguration(ParamsApplication paramsApplication) {
		dbService.setApplicationCore(paramsApplication);
        dbService.setAllConfig(paramsApplication);
        return  dbService.saveOrDoNothingApplicationAllInfo(paramsApplication);
	}
    
    /**********************************************************
     * 
     *                     Validator          
     * 
     **********************************************************/

	/**********************************************************
     * 
     *              Others
     * 
     **********************************************************/
    private List batchCreateRc(List<ParamsApplication> deployerParams,String ip) throws  Exception{
        List resList = new ArrayList<>();
        for(ParamsApplication pa :deployerParams ){
            pa.setIp(ip);
            //System.out.println(pa.applicationCore.getApplicationCoreId());
            //System.out.println(pa.configBasic.getConfigBasicCpu()+pa.configBasic.getConfigBasicMemory()+pa.configBasic.getConfigBasicImagePullSecret());
            Map<String,Object> deployerMap = appService.getDeployerCreateRc(pa);
            resList.add(deployerMap);
            //need to reset application instance relation table.
            Integer instanceCoreId = (Integer)((Map<String,Object>)deployerMap.get("DbInfo")).get("instanceCoreId");
            if(instanceCoreId.intValue()>0){
                this.dbService.updateInstanceCoreId(pa.getAir(),instanceCoreId);
                this.eventsService.insertOneEvent(pa.applicationCore.getApplicationCoreId(),
                        "CreateRc","成功创建实例："+(String)deployerMap.get("InstanceName"));
            }

            //need to create services:
        }
        return resList;
    }

    private List batchDeleteRc(List<ParamsApplication> deployerParams){
        List resList = new ArrayList<>();
        for(ParamsApplication pa :deployerParams ){
            Map<String,Object> deployerMap = appService.getDeployerDeleteRc(pa);
            //reset appplication instance relation table.
            if((Boolean)deployerMap.get("deleteStatus")){
                this.dbService.setApplicationInstanceRelationInvalid(pa);
                this.eventsService.insertOneEvent(pa.applicationCore.getApplicationCoreId(),
                        "DeleteRc","成功删除实例："+pa.applicationCore.getApplicationCoreRename());
            }
            //delete service first.

            resList.add(deployerMap);
        }
        return resList;
    }


    @RequestMapping("createRawApplication.do")
    public @ResponseBody
    Map createRawApplication(ParamsApplication paramsApplication){
        if(!this.checkService.checkCreateRawApplication(paramsApplication)){
            return this.errorParams();
        }
        Map<String ,Object> resMap1 = dbService.checkApplicationNameByRuntime(paramsApplication);
        if(((Boolean)resMap1.get("exist")).equals(false)){
            return resMap1;
        }
        paramsApplication = dbService.setApplicationCore(paramsApplication);
        Map<String ,Object> resMap = dbService.saveRawApplicationCoreInfo(paramsApplication);
        if((Boolean)resMap.get("success")){
            this.eventsService.insertOneEvent((Integer) resMap.get("applicationCoreId"),
                    "CreateRawApplication","成功构建一个空应用："+(String)resMap.get("applicationCoreRename"));
        }
        return resMap;
    }

    @RequestMapping("addConfigVersion.do")
    public @ResponseBody
    Map addConfigVersion(ParamsApplication paramsApplication){
        if(!this.checkService.checkAddConfigVersion(paramsApplication)){
            return this.errorParams();
        }
        if(paramsApplication.cc != null &&
                paramsApplication.cc.getConfigCoreId() !=null &&
                this.dbService.getCcm().selectByPrimaryKey(paramsApplication.cc.getConfigCoreId())==null){
            return this.errorParams();
        }
        paramsApplication.applicationCore = this.dbService.getApplicationCoreById(paramsApplication.applicationCore.getApplicationCoreId());
        if(paramsApplication.applicationCore == null){
            return this.errorParams();
        }
        paramsApplication = dbService.setAllConfig(paramsApplication);
        if(paramsApplication.cc != null && paramsApplication.cc.getConfigCoreId() !=null){
            paramsApplication = dbService.compareAndSetAllConfig(paramsApplication);
        }
        Integer currentConfigId = -1;
        if(paramsApplication.cc ==null||paramsApplication.cc.getConfigCoreId() == null){
            System.out.println("good");
            currentConfigId = this.dbService.saveApplicationConfigInfo(paramsApplication);
            return new HashMap<String,Object>(){
                {
                    put("message","新建了一个配置版本");
                    put("success",true);
                }
            };
        }
        else{
            currentConfigId = paramsApplication.cc.getConfigCoreId();
            return new HashMap<String,Object>(){
                {
                    put("message","当前配置版本没有更改");
                    put("success",true);
                }
            };
        }
    }

    @RequestMapping("constructApplicationConfig.do")
    public @ResponseBody
    Map<String,Object> constructForRawApplication(ParamsApplication paramsApplication){
        if(!this.checkService.checkConstructForRawApplication(paramsApplication)){
            return this.errorParams();
        }
       // System.out.println(this.dbService.getCcm().selectByPrimaryKey(paramsApplication.cc.getConfigCoreId()));
        if(paramsApplication.cc != null &&
                paramsApplication.cc.getConfigCoreId() !=null &&
                this.dbService.getCcm().selectByPrimaryKey(paramsApplication.cc.getConfigCoreId())==null){
            return this.errorParams();
        }
        //System.out.println(paramsApplication.instanceImage.getConfigImageCommands());
        Map<String,Object> resMap = new HashMap<>();
        //System.out.println(paramsApplication.applicationCore.getApplicationCoreId());
        paramsApplication.applicationCore = this.dbService.getApplicationCoreById(paramsApplication.applicationCore.getApplicationCoreId());
        if(paramsApplication.applicationCore == null){
            return this.errorParams();
        }
        paramsApplication = dbService.setAllConfig(paramsApplication);
        if(paramsApplication.cc != null && paramsApplication.cc.getConfigCoreId() !=null){
            System.out.println("good2");
            paramsApplication = dbService.compareAndSetAllConfig(paramsApplication);
        }
        //System.out.println(paramsApplication.instanceImage.getConfigImageCommands());
        //System.out.println("coreId:"+paramsApplication.applicationCore.getApplicationCoreId());
        Map<String,Object> applicationInfo = dbService.saveOrDoNothingApplicationAllInfo(paramsApplication);

        //resMap.put("devops-application",applicationInfo);
        if(applicationInfo.get("applicationInstanceRelation") != null){
            List<ParamsApplication> deployerParams = this.dbService.getAllInfoByApplicationInstanceRelationIds((String)applicationInfo.get("applicationInstanceRelation"));
            //resMap.put("createRcResults",this.batchCreateRc(deployerParams,paramsApplication.getIp()));
            try {
                this.batchCreateRc(deployerParams,paramsApplication.getIp());
                resMap.put("success",true);
            } catch (Exception e) {
                resMap.put("success",false);
                resMap.put("message","K8s集群环境异常，请联系管理员或者修改参数重新配置！");
            }
            //this.dbService.updateApplicationImageCount(paramsApplication);

        }
        else{
            resMap.put("success",false);
        }
        return resMap;
    }

    @RequestMapping("getApplicationListByUsername.do")
    public @ResponseBody
    Map getApplicationListByUsername(ParamsApplication paramsApplication,int page,int rows){
        return this.dbService.getApplicationListByUsername(paramsApplication,page,rows);
    }

    @RequestMapping("getApplicationListByMultipleFields.do")
    public @ResponseBody
    Map getApplicationListByMultipleFields(ParamsApplication paramsApplication,int page,int rows){
        return this.dbService.getApplicationListByMultipleFields(paramsApplication,page,rows);
    }

    @RequestMapping("getApplicationDetails.do")
    public @ResponseBody
    Map getApplicationDetails(ParamsApplication paramsApplication){
        return this.dbService.getApplicationDetails(paramsApplication);
    }

    @RequestMapping("getApplicationConfigVersion.do")
    public @ResponseBody
    Object getApplicationConfigVersion(ParamsApplication paramsApplication){
        return this.dbService.getApplicationConfigVersion(
                paramsApplication.applicationCore.getApplicationCoreId());
    }

    @RequestMapping("getOneApplicationConfigInfo.do")
    public @ResponseBody
    Object getOneApplicationConfigInfo(ParamsApplication paramsApplication){
        return this.dbService.getConfigInfoByConfigCoreId(paramsApplication.air.getConfigCoreId());
    }

    @RequestMapping("getApplicationImageVersion.do")
    public @ResponseBody
    Object getApplicationImageVersion(ParamsApplication paramsApplication,int page,int rows){
        return this.dbService.getApplicationImageVersion(paramsApplication.applicationCore.getApplicationCoreId(),page,rows);
    }

    //dilation,shrinkage
    @RequestMapping("changePolicy.do")
    public @ResponseBody
    Map changePolicy(Integer policyIndex,ParamsApplication paramsApplication){
        if(paramsApplication.instanceCount !=null){
            System.out.println(paramsApplication.instanceCount);
            paramsApplication.instanceReplica = this.dbService.resetInstanceReplica(policyIndex,paramsApplication);
        }
        List<ParamsApplication> paList = this.dbService.airList2paList(policyIndex,paramsApplication);
        Map<String,Object> resMap = new HashMap<>();
        if(paList.size() == 0){
            return new HashMap<String,Object>(){
                {
                    put("message","不支持的策略或伸缩参数无效!");
                    put("success",false);
                }
            };
        }
        for(ParamsApplication pa:paList ){
            System.out.println(pa.instanceImage);
            System.out.println(pa.instanceImage.getConfigImageName());
        }
        if(paList.get(0).air.getApplicationInstanceCurrentStatus() ==null){
            //resMap.put("createInstanceInfo",this.batchCreateRc(paList,"40.125.203.202"));
            try {
                this.batchCreateRc(paList,paramsApplication.ip);
            } catch (Exception e) {
                e.printStackTrace();
                resMap.put("success",false);
                resMap.put("message","集群环境异常！");
            }
        }
        else if(paList.get(0).air.getApplicationInstanceCurrentStatus().equals("created")){
            //resMap.put("deleteInstanceInfo",this.batchDeleteRc(paList));
            this.batchDeleteRc(paList);
            resMap.put("success",true);
        }

        return resMap;
    }

    @RequestMapping("changeDeployer.do")
    public @ResponseBody
    Map changeDeployer(ParamsApplication paramsApplication,ParamsDeployerConversion pdc){

        System.out.println(paramsApplication.getIp());
        if(pdc.oldVersion.equals(pdc.currentVersion)){
            return new HashMap<String,Object>(){
                {
                    put("message","新旧版本一样，不需要变更!");
                    put("success",false);
                }
            };
        }
        ParamsApplication old = this.dbService.getOldParamsConversion(paramsApplication,pdc);
        ParamsApplication current = null;
        if(old !=null)
            current = this.dbService.getCurrentParamsConversion(paramsApplication,pdc,old.needDoneNum);
        if(old == null || current == null){
            return new HashMap<String,Object>(){
                {
                    put("message","不支持的部署变更参数!");
                    put("success",false);
                }
            };
        }
        Map<String,Object> resMap = new HashMap<>();
        resMap.put("oldInfo",this.changePolicy(1,old));
        resMap.put("currentInfo",this.changePolicy(0,current));
        resMap.put("success",true);
        return resMap;
    }

    @RequestMapping("getApplicationEvents.do")
    public @ResponseBody
    Map getApplicationEvents(ApplicationEvents ae, Integer page, Integer rows){
        return this.eventsService.getApplicationEvents(ae,page,rows);
    }

    @RequestMapping("deleteApplication.do")
    public @ResponseBody
    Map deleteApplication(ParamsApplication pa){
        List<ParamsApplication> paList = this.dbService.getAllAir(pa.applicationCore.getApplicationCoreId());
        if(paList.size() >0){
            this.batchDeleteRc(paList);
            this.dbService.deleteApplicationCore(pa.applicationCore.getApplicationCoreId());
            return new HashMap<String,Object>(){
                {
                    put("message","删除实例个数："+paList.size());
                    put("success",true);
                }
            };
        }
        else {
            this.dbService.deleteApplicationCore(pa.applicationCore.getApplicationCoreId());
            return new HashMap<String,Object>(){
                {
                    put("message","该应用当前没有实例");
                    put("success",true);
                }
            };
        }
    }

    @RequestMapping("getApplicationStatisticalInfo.do")
    public @ResponseBody
    Map getApplicationatisticalInfo(ParamsApplication pa){
        if(pa.applicationCore == null)
            pa.applicationCore = new ApplicationCore();
        if(pa.envId == 0){
            pa.applicationCore.setApplicationRuntimeId(null);
        }
        else{
            pa.applicationCore.setApplicationRuntimeId(pa.envId);
        }
        return this.dbService.getApplicationStatisticalInfo(pa);
    }
}
